package pl.rzarajczyk.breaktime.utils;

import com.google.common.io.ByteStreams;
import java.awt.Component;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileSystemView;
import org.apache.commons.logging.Log;

/**
 *
 * @author rzarajczyk
 */
public class Utils {

    public static int SECOND = 1000;
    
    private static FileSystemView fsv = FileSystemView.getFileSystemView();
    
    // -------------------------------------------------------------------------
    
    /**
     * For JUnit tests
     * @param fileSystemView 
     */
    static void setFileSystemView(FileSystemView fileSystemView) {
        fsv = fileSystemView;
    }
    // -------------------------------------------------------------------------

    public static String toTimeString(int ms) {
        boolean negative = ms < 0;
        if ( negative ) {
            ms = -ms;
        }
        int sec = ms / Utils.SECOND;
        int min = sec / 60;
        sec = sec % 60;
        StringBuilder result = new StringBuilder();
        if ( negative ) {
            result.append("-");
        }
        result.append(min < 10 ? "0" + min : min);
        result.append(":");
        result.append(sec < 10 ? "0" + sec : sec);
        return result.toString();
    }

    public static int parseTimeString(String str) {
        int multiplier = 1;
        if ( str.trim().startsWith("-") ) {
            multiplier = -1;
        }
        String [] parts = str.split(":");
        if ( parts.length != 2 ) {
            throw new IllegalArgumentException("Unable to parse string: " + str);
        }
        int minutes = Math.abs( Integer.parseInt(parts[0]) );
        int seconds = Integer.parseInt(parts[1]);
        if ( seconds < 0 )
            throw new IllegalArgumentException("Unable to parse string: " + str);
        return ( minutes * 60 + seconds ) * Utils.SECOND * multiplier;
    }

    public static File getSettingsDir() throws IOException {
        File dir = fsv.getHomeDirectory();
        dir = new File(dir, ".breaktime");
        if ( ! dir.exists() ) {
            if ( ! dir.mkdirs() )
                throw new IOException("Could not create directory structure: " + dir.getAbsolutePath());
        }
        return dir;
    }

    public static File getTempDir() throws IOException {
        File file = File.createTempFile("breaktime-temp-file", ".tmp");
        File dir = file.getParentFile();
        file.delete();
        
        return dir;
    }

    public static void error(Component parent, Log log, String message, Throwable e) {
        log.error(message, e);
        JOptionPane.showMessageDialog(parent, message + ":\n" + getActualCause(e).getLocalizedMessage(), "Error occured", JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }

    public static Throwable getActualCause(Throwable t) {
        while ( t.getCause() != null )
            t = t.getCause();
        return t;
    }

    static JarFile openCurrentJar() throws IOException {
        Class<?> clazz = Utils.class;
        try {
            URI uri = clazz.getProtectionDomain().getCodeSource().getLocation().toURI();
            return new JarFile(uri.getPath());
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }

    public static void unpackFromClasspathDir(String classpathResource, File dir) throws IOException {
        JarFile jarFile = openCurrentJar();
        try {
            Enumeration<JarEntry> enumeration = jarFile.entries();
            while (enumeration.hasMoreElements()) {
                JarEntry entry = enumeration.nextElement();
                String name = entry.getName();
                if ( name.startsWith(classpathResource) ) {
                    if ( name.endsWith("/") ) {
                        File subdir = new File(dir, name);
                        if ( ! subdir.mkdirs() )
                            throw new IOException("Could not create dir: " + subdir);
                    } else {
                        name = "/" + name;
                        File file = new File(dir, name);
                        InputStream input = Utils.class.getResourceAsStream(name);
                        OutputStream output = new BufferedOutputStream(new FileOutputStream(file));
                        try {
                            ByteStreams.copy(input, output);
                        } catch (IOException e) {
                            throw new IOException("Error during copying from classpath:" + name + " to file:" + file, e);
                        } finally {
                            output.close();
                        }
                    }
                }
            }
        } finally {
            jarFile.close();
        }
    }
    
    public static boolean isWindows() {
        String os = System.getProperty("os.name").toLowerCase();
        return os.contains("win");
    }

    public static boolean isMac() {
        String os = System.getProperty("os.name").toLowerCase();
        return os.contains("mac");
    }

    public static boolean isUnix() {
        String os = System.getProperty("os.name").toLowerCase();
        return os.contains("nix") || os.contains("nux");
    }
    
    public static void setProperty(Object object, String name, int value) {
        try {
            name = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
            Class<?> clazz = object.getClass();
            Method method = clazz.getMethod(name, int.class);
            method.invoke(object, value);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

}